package edu.rpi.bt.client;


import java.util.Iterator;
import java.util.List;

import com.apress.progwt.client.college.ServiceCache;
import com.apress.progwt.client.rpc.StdAsyncCallback;
import com.google.gwt.core.client.JavaScriptObject;
import com.gwtext.client.core.EventObject;
import com.gwtext.client.util.JavaScriptObjectHelper;
import com.gwtext.client.widgets.Button;
import com.gwtext.client.widgets.MessageBox;
import com.gwtext.client.widgets.Toolbar;
import com.gwtext.client.widgets.ToolbarButton;
import com.gwtext.client.widgets.event.ButtonListenerAdapter;
import com.gwtext.client.widgets.form.Field;
import com.gwtext.client.widgets.form.TextField;
import com.gwtext.client.widgets.form.event.TextFieldListenerAdapter;
import com.gwtext.client.widgets.map.BoundingBox;
import com.gwtext.client.widgets.map.GoogleMap;
import com.gwtext.client.widgets.map.GoogleMarker;
import com.gwtext.client.widgets.map.LatLonPoint;
import com.gwtext.client.widgets.map.MapPanel;

import edu.rpi.bt.client.domain.Destination;

/*
 * Adapted from http://abhijeetmaharana.com
 */
public class MapModule {
    private ServiceCache serviceCache;
    
    final MapModule thisModule = this;

    public AddressStore addressStore;
    
    private int width = 900;
    private int height = 400;
    private String startLoc = "110 8th Street, Troy, NY";
    private BoundingBox bb;
    
    private String messages = "";
    
//    Panel viewportPanel;
    MapPanel mapPanel; 
//    Panel eastPanel;
    
    private List<Destination> locations;
    
    TextField addressField;
    ToolbarButton refreshMapButton;
    
    MapModule(ServiceCache servCache ) {
        this.serviceCache = servCache;
        init();
    }
    
    MapModule(ServiceCache servCache, int width, int height){
        this.serviceCache = servCache;
        this.width = width;
        this.height = height;
        init();
    }

    MapModule(ServiceCache servCache, int width, int height, String startLoc ){
        this.serviceCache = servCache;
        this.width = width;
        this.height = height;
        this.startLoc = startLoc;
        init();
    }

    private void init(){
        createMapPanel();
        addMapControls();
        updateMap(this.startLoc, JavaScriptObjectHelper.createObject(), this);
    }
    
    private void createMapPanel()
    {
        mapPanel = new GoogleMap();
        mapPanel.setHeight(this.height);
        mapPanel.setWidth(this.width);
        mapPanel.addLargeControls();
        mapPanel.setStyle("btGoogpanel");
    }
    
    private void addMapControls()
    {
        
        addressField = new TextField(){{
            setWidth(300);
            setValue(startLoc);
            
            // Gotta add this so you can press 'enter' to submit
            addListener( new TextFieldListenerAdapter(){
                public void onSpecialKey(Field field, EventObject e){
                    int keypressed = e.getKey();
                    if( keypressed == 13 ){
                        String address = addressField.getText();
                        if (!address.trim().equals("")){
                            updateMap(address, JavaScriptObjectHelper.createObject(), thisModule);
                        }
                    }
                }
            });
        }};
        
        refreshMapButton = new ToolbarButton("Refresh map", new ButtonListenerAdapter() {
            public void onClick(Button button, EventObject e) {
                String address = addressField.getText();
                if (!address.trim().equals(""))
                    updateMap(address, JavaScriptObjectHelper.createObject(), thisModule);
            }
        });
        
        Toolbar toolbar = new Toolbar();
        toolbar.addText("Enter any address or location name: ");
        toolbar.addField(addressField);
        toolbar.addSpacer();
        toolbar.addButton(refreshMapButton);
        
        mapPanel.setTopToolbar(toolbar);
    }
    
    public native void updateMap(String locationAddress, JavaScriptObject llp, MapModule thisModule) /*-{
        var geo = new $wnd.GClientGeocoder();
        
        geo.getLocations(locationAddress, 
            function(response) 
            {
                if (!response || response.Status.code != 200) 
                {
                    alert("Unable to geocode that address");
                } 
                else 
                {
                    var place = response.Placemark[0];
                    llp.lat = place.Point.coordinates[1];
                    llp.lon = place.Point.coordinates[0];
                    llp.address = place.address;
                    thisModule.@edu.rpi.bt.client.MapModule::renderMap(Lcom/google/gwt/core/client/JavaScriptObject;)(llp);
                }
            }
        );
    }-*/;
    
    
    public void renderMap(JavaScriptObject jsObj)
    {
        double lat = Double.parseDouble(JavaScriptObjectHelper.getAttribute(jsObj, "lat"));
        double lon = Double.parseDouble(JavaScriptObjectHelper.getAttribute(jsObj, "lon"));
       
        addressStore.address = JavaScriptObjectHelper.getAttribute(jsObj, "address");
        addressStore.latLon = new LatLonPoint(lat, lon);
        
        mapPanel.setCenterAndZoom(addressStore.latLon, 10);
       
        
        
        bb = mapPanel.getBounds();
        getLocations(bb);
        
        // alert( "Bounding box:\nNE Corner: " +  bb.getNorthEast().toString() + "\nSW Corner: " + bb.getSouthWest().toString());
        
        // Now we want to get all the points in the Bounding Box here
  
        // This is a dummy...
        Destination destination = new Destination();
        destination = new Destination();
        destination.setDescription("This is the description of the location in general. Quisque nec tellus. In sit amet eros nec libero condimentum ultrices. Duis eu nisl. Sed posuere, ante eu facilisis posuere, tortor quam sollicitudin neque, accumsan ullamcorper elit ligula eu erat.");
        destination.setName("The Location Name Goes Here");
        Destination[] locations = { destination };
        // OnSuccess call:
       //  processLocations( locations );
    }
    public void renderAllMap(List<Destination> allLocations){

        int size = allLocations.size();
        LatLonPoint[] lineList = new LatLonPoint[size];
        //for(int i=0;i<size;i++){
        //    lineList[i] = new LatLonPoint(allLocations.get(i).getLatitude(),allLocations.get(i).getLongitude());
        //}
        //Polyline p = new Polyline(lineList);
        //mapPanel.addPolyline(p);
        processLocations(allLocations);
        mapPanel.autoCenterAndZoom();
    }
    
    private void processLocations( List<Destination> locations ){
        Destination destination;
        messages = "";
        // Clear and start over.
        mapPanel.removeAllMarkers();
        
        // Create the marker for the address search
        GoogleMarker gm = new GoogleMarker(addressStore.latLon);
        gm.setIcon("http://www.google.com/mapfiles/arrow.png");
        mapPanel.addMarker( gm );
        
        
        for (Iterator<Destination> it = locations.iterator(); it.hasNext();) {
            // Set the destination
            // destination = locations[i];
            destination = (Destination)it.next();

            messages += destination.getAddress() + "<br>" ;
            messages += "("+destination.getLatitude() + ", " + destination.getLongitude() + ")<br>";
            
            // Create the marker for the location 
            gm = new GoogleMarker(
                    new LatLonPoint( destination.getLatitude(), destination.getLongitude() )
                    );
            gm.setIcon("http://www.google.com/mapfiles/marker.png");
    

            // Get the data for the info bubble panel
            LocationPanelSmall lps = new LocationPanelSmall( serviceCache, destination );
            
            // Set info bubble
            gm.setInfoBubble(lps);
            
            // TODO Add marker to a list of markers, so when you move the map we don't have to keep
            //      building these markers

            // TODO Add listener to pop up the small-one when you hover, the big one when you click
            //
            //      addListenerToMarker( gm.toGoogle(), gm  );
            //      gm.addListener("mouseover", alert("Mouseover!") );

        
            mapPanel.addMarker( gm );
            messages += "added location marker<br>";
        }
        
        //MessageBox.alert(messages);
    }
 
    //public void getLocations(double lat, double lon){
       // serviceCache.getAllDestinations(new StdAsyncCallback<List<Destination>>("Get locations"){
    public void getLocations(BoundingBox bb){
        messages += "BB " + bb.toString() + "<br>";
        LatLonPoint  ne=bb.getNorthEast();
        LatLonPoint sw=bb.getSouthWest();
        
        messages += "SW:(" + sw.getLat() + "," + sw.getLon() + ") NE:( " + ne.getLat() + ", "+ ne.getLon() +")<br>";
        
    //    serviceCache.getAllLocations(123.00, 20.20, new StdAsyncCallback<List<Destination>>("Get locations"){
     //    serviceCache.getAllLocations(123.00, 20.20, 133.00, 30.30, new StdAsyncCallback<List<Destination>>("Get locations"){
        serviceCache.getAllLocations(sw.getLat(), sw.getLon(), ne.getLat(), ne.getLon(), new StdAsyncCallback<List<Destination>>("Get locations"){
        public void onSuccess(List<Destination> result) {
                super.onSuccess(result);
                if (result == null) {
                    MessageBox.alert("result for dest null"); 
                } else {
                    messages += "load(result)<br>";
                    load(result);
                    messages += "processLocations(result)<br>";
                    processLocations(result);
                }
            }

            public void onFailure(Throwable caught) {
                super.onFailure(caught);
              
            }
        });
    }
    
    public void load(List<Destination> dests){
        messages += "adding destination<br>"; 
        this.locations=dests;
        messages += "Num of destinations " + getDestinations().size() + "<br>";
        
    }
    public void setTextField(String text){
        addressField.setValue(text);
    }
    public  List<Destination> getDestinations(){
        //   System.out.println("inside getdests");
           //MessageBox.alert("inside get destination"); 
           return this.locations;
       }
    public static native void alert(String msg)/*-{
        $wnd.alert(msg);
    }-*/;
    
    private native void addListenerToMarker(JavaScriptObject markerJS, GoogleMarker thisMarker)/*-{
    var self = this;
    $wnd.GEvent.addListener(markerJS, 'click', function(coords) {
              alert('marker at ' + coords + ' clicked');
         });
         
    }-*/;
}
